<template>
  <a-modal
    :width="750"
    :title="modal.title"
    :visible="modal.show"
    :confirmLoading="modal.load"
    :maskClosable="false"
    @ok="handleSave"
    @cancel="closeModal"
    centered
    forceRender
  >
    <a-row>
      <a-col :span="14">
        <canvas
          ref="canvas"
          class="avatar-canvas"
          :width="canvas.w"
          :height="canvas.h"
          @mousedown="canvasMouseDown"
          @mousemove="canvasMouseMove"
          @mouseout="canvasMouseOut"
          @mouseup="canvasMouseUp"
        />
        <div class="icon-wrapper">
          <a-icon type="minus" @click="subScale" />
          <a-slider v-model="canvas.scale" :step="0.1" :min="1" :max="2" @change="setAvatarDelay" />
          <a-icon type="plus" @click="addScale" />
        </div>
        <div class="icon-wrapper">
          <a-icon type="undo" @click="subRotate" />
          <a-slider v-model="canvas.rotate" :step="1" :min="0" :max="360" @change="setAvatarDelay" />
          <a-icon type="redo" @click="addRotate" />
        </div>
      </a-col>
      <a-col :span="10">
        <div class="avatar-container">
          <a-avatar :size="140" :src="avatar.url" class="avatar-icon" />
          <a-upload
            class="avatar-upload avatar-item"
            :file-list="avatar.fileList"
            :before-upload="selectImg"
          >
            <a-button>
              <a-icon type="upload" />重新上传
            </a-button>
          </a-upload>
          <div
            style="font-size:12px;line-height:18px;padding:20px;"
          >图片尺寸需要大于140 * 140像素，支持jpg、png、jpeg等格式，大小不能超过2MB。</div>
          <!-- <a-button @click="download" class="avatar-item" icon="download"> Download </a-button>
          <a-button @click="setAvatar" class="avatar-item" icon="setting"> Set Avatar </a-button>-->
          <!-- <a-button @click="getImageData" class="avatar-item" icon="windows"> Get Image Data </a-button> -->
        </div>
      </a-col>
    </a-row>
  </a-modal>
</template>

<script>
import { settingUpload } from '@/services/sys'
import { dataURLtoFile } from '@/utils/util'

const canvasWidth = 400
const canvasHeight = 300

export default {
  computed: {},
  methods: {
    open (params) {
      this.addTransform(params)
      this.modal.show = true
    },
    addTransform (file) {
      this.$refs.canvas.style.backgroundColor = '#333'
      const { w, h } = this.canvas
      this.ctx = this.$refs.canvas.getContext('2d')
      this.ctx.clearRect(0, 0, w, h)
      this.avatar.file = null
      this.avatar.url = null
      this.avatar.img = null
      this.resetCanvas()
      this.selectImg(file)
      return {}
    },
    transFormImg () {
      if (this.ctx instanceof CanvasRenderingContext2D) {
        const {
          w,
          h,
          scale,
          rotate,
          offset: { x: offsetX, y: offsetY }
        } = this.canvas
        this.ctx.save()
        this.ctx.fillStyle = '#333'
        this.ctx.clearRect(0, 0, w, h)

        // 移动
        this.ctx.translate(offsetX, offsetY)

        // 中心旋转
        this.ctx.translate(this.centerPoint.x, this.centerPoint.y)
        this.ctx.rotate((rotate * Math.PI) / 180)
        this.ctx.translate(-this.centerPoint.x, -this.centerPoint.y)

        // 中心缩放
        this.ctx.translate(
          this.centerPoint.x * (1 - scale),
          this.centerPoint.y * (1 - scale)
        )
        this.ctx.scale(scale, scale)

        this.drawImg()
        this.ctx.restore()

        // 设置蒙版
        this.ctx.save()
        this.ctx.fillStyle = '#333333'
        this.ctx.globalAlpha = 0.5
        this.ctx.fillRect(0, 0, 50, h)
        this.ctx.fillRect(w - 50, 0, 50, h)
        this.ctx.restore()

        this.requestId = window.requestAnimationFrame(this.transFormImg)
      }
    },
    drawImg () {
      if (
        this.ctx instanceof CanvasRenderingContext2D &&
        this.avatar.img instanceof Image
      ) {
        const { width, height } = this.avatar.img
        const { w, h } = this.canvas
        const imgWR = width / h
        const imgHR = height / h
        const imgW = imgWR <= imgHR ? width / imgWR : width / imgHR
        const imgH = imgWR <= imgHR ? height / imgWR : height / imgHR
        const imgY = h / 2 - imgH / 2
        const imgX = w / 2 - imgW / 2
        this.ctx.drawImage(
          this.avatar.img,
          Math.floor(imgX),
          Math.floor(imgY),
          Math.floor(imgW),
          Math.floor(imgH)
        )
        this.canvas.img = {
          x: Math.floor(imgX),
          y: Math.floor(imgY),
          w: Math.floor(imgW),
          h: Math.floor(imgH)
        }
      }
    },
    selectImg (file) {
      this.avatar.fileList = []
      this.avatar.file = file

      const { w, h } = this.canvas
      this.ctx.clearRect(0, 0, w, h)

      // 从file对象中获取base64
      const reader = new FileReader()
      reader.readAsDataURL(file)
      reader.onload = (e) => {
        this.avatar.url = e.target.result

        // base64转换成image
        const img = new Image()
        img.src = e.target.result
        img.onload = () => {
          this.avatar.img = img
          // 绘图
          this.resetCanvas()
          if (this.requestId) window.cancelAnimationFrame(this.requestId)
          this.transFormImg()
          this.setAvatarDelay()
        }
      }
      return false
    },
    download () {
      if (
        this.ctx instanceof CanvasRenderingContext2D &&
        this.avatar.file instanceof File
      ) {
        const imgData = this.ctx.getImageData(
          50,
          0,
          this.canvas.h,
          this.canvas.h
        )
        const canvas = document.createElement('canvas')
        canvas.width = 300
        canvas.height = 300
        const ctx = canvas.getContext('2d')
        ctx.putImageData(imgData, 0, 0)

        const imgUrl = canvas.toDataURL('image/png')
        // const imgUrl = this.$refs.canvas.toDataURL("image/png")
        const a = document.createElement('a')
        const event = new MouseEvent('click')
        a.download = this.avatar.file.name
        a.href = imgUrl
        a.dispatchEvent(event)
      }
    },
    getImageData () {
      if (this.ctx instanceof CanvasRenderingContext2D) {
        const {
          img: { x: imgX, y: imgY, w: imgW, h: imgH }
        } = this.canvas
        console.log('left', this.ctx.getImageData(imgX, imgY, 10, imgH))
        console.log(
          'right',
          this.ctx.getImageData(imgX + imgW - 1, imgY, 5, imgH)
        )
        console.log('top', this.ctx.getImageData(imgX, imgY, imgW, 5))
        console.log(
          'bottom',
          this.ctx.getImageData(imgX, imgY + imgH - 1, imgW, 5)
        )
      }
    },
    setAvatar () {
      if (this.ctx instanceof CanvasRenderingContext2D) {
        const imgData = this.ctx.getImageData(
          50,
          0,
          this.canvas.h,
          this.canvas.h
        )
        const canvas = document.createElement('canvas')
        canvas.width = 300
        canvas.height = 300
        const ctx = canvas.getContext('2d')
        ctx.putImageData(imgData, 0, 0)
        const imgUrl = canvas.toDataURL('image/png')
        this.avatar.url = imgUrl
      }
    },
    setAvatarDelay () {
      let timeout
      return (() => {
        if (!timeout) {
          timeout = setTimeout(() => {
            timeout = null
            this.setAvatar()
          }, 200)
        }
      })()
    },
    canvasMouseMove (event) {
      if (this.canvas.down) {
        if (this.canvas.mouseEvent === null) this.canvas.mouseEvent = event
        else {
          const { movementX, movementY, offsetX, offsetY } =
            this.canvas.mouseEvent
          // IE 无movementX和movementY
          if (movementX !== undefined && movementY !== undefined) {
            this.canvas.offset.x = movementX + this.canvas.offset.x
            this.canvas.offset.y = movementY + this.canvas.offset.y
          } else {
            this.canvas.offset.x =
              -(offsetX - event.offsetX) + this.canvas.offset.x
            this.canvas.offset.y =
              -(offsetY - event.offsetY) + this.canvas.offset.y
          }
          this.canvas.mouseEvent = event
          this.setAvatarDelay()
        }
      }
    },
    canvasMouseDown () {
      this.canvas.down = true
    },
    canvasMouseOut () {
      this.canvas.down = false
      this.canvas.mouseEvent = null
    },
    canvasMouseUp () {
      this.canvas.down = false
      this.canvas.mouseEvent = null
    },
    addScale () {
      if (this.canvas.scale === 2) return
      this.canvas.scale += 0.1
      this.setAvatarDelay()
    },
    subScale () {
      if (this.canvas.scale === 1) return
      this.canvas.scale -= 0.1
      this.setAvatarDelay()
    },
    addRotate () {
      if (this.canvas.scale === 360) return
      this.canvas.rotate += 1
      this.setAvatarDelay()
    },
    subRotate () {
      if (this.canvas.rotate === 0) return
      this.canvas.rotate -= 1
      this.setAvatarDelay()
    },
    resetCanvas () {
      this.canvas.scale = 1
      this.canvas.rotate = 0
      this.canvas.down = false
      this.canvas.offset.x = 0
      this.canvas.offset.y = 0
      this.canvas.mouseEvent = null
      this.canvas.img = { x: 0, y: 0, w: 0, h: 0 }
    },
    async handleSave () {
      const file = dataURLtoFile(this.avatar.url, this.avatar.file.name)
      const form = new FormData()
      form.append('file', file)
      const res = await settingUpload(form)
      const { isSuccess, data, msg } = res
      if (isSuccess) {
        this.closeModal()
        this.$emit('ok', data.url)
      } else {
        this.$message.newFun(msg, 'error', 3)
      }
    },
    closeModal () {
      if (this.requestId) window.cancelAnimationFrame(this.requestId)
      this.modal.show = false
      this.modal.load = false
    },
    // 计算宽高比公式
    gcd (a, b) {
      // const r = this.gcd(width, height)
      // const wr = width/r
      // const hr = height/r
      // console.log(width, height, r, wr, hr)
      // widthT = heightT * Aspect Ratio
      // heightT = widthT / Aspect Ratio
      return b === 0 ? a : this.gcd(b, a % b)
    },
    scaleWH () {
      const { w, h } = this.canvas
      const r = this.gcd(w, h)
      return { w, h, r }
    }
  },
  data () {
    return {
      canvas: {
        w: canvasWidth,
        h: canvasHeight,
        scale: 1,
        rotate: 0,
        down: false,
        offset: { x: 0, y: 0 },
        mouseEvent: null,
        img: { x: 0, y: 0, w: 0, h: 0 }
      },
      limit: { w: 300, h: 300 },
      centerPoint: Object.freeze({ x: canvasWidth / 2, y: canvasHeight / 2 }),
      ctx: null,
      requestId: null,
      modal: {
        url: settingUpload,
        title: '修改头像',
        show: false,
        load: false
      },
      avatar: {
        fileList: [],
        file: null,
        url: null,
        img: null
      }
    }
  }
}
</script>

<style lang="less" scoped>
.avatar-canvas {
  border: 1px solid;
}

.avatar-container {
  text-align: center;

  .avatar-icon {
    margin-bottom: 12px;
    display: block;
    border:1px solid #d9d9d9;
    left: calc(50% - 70px);
  }

  .avatar-upload {
    display: block;
  }

  .avatar-item {
    margin-bottom: 12px;
  }
}
</style>

<style scoped>
.icon-wrapper {
  position: relative;
  padding: 0px 30px;
}

.icon-wrapper .anticon {
  position: absolute;
  top: -2px;
  width: 16px;
  height: 16px;
  line-height: 1;
  font-size: 16px;
  color: rgba(0, 0, 0, 0.25);
}

.icon-wrapper .anticon:first-child {
  left: 0;
}

.icon-wrapper .anticon:last-child {
  right: 0;
}
</style>
